package com.yourcompany.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yourcompany.api.dto.MenuDTO;
import com.yourcompany.api.entity.Menu;
import com.yourcompany.api.mapper.MenuMapper;
import com.yourcompany.api.service.MenuService;
import com.yourcompany.api.vo.MenuVO;
import com.yourcompany.common.exception.BusinessException;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createMenu(MenuDTO menuDTO) {
        // 检查菜单编码是否存在
        if (count(new LambdaQueryWrapper<Menu>()
                .eq(Menu::getCode, menuDTO.getCode())) > 0) {
            throw new BusinessException("菜单编码已存在");
        }

        // 检查父级菜单是否存在
        if (menuDTO.getParentId() != null && menuDTO.getParentId() != 0) {
            Menu parentMenu = getById(menuDTO.getParentId());
            if (parentMenu == null) {
                throw new BusinessException("父级菜单不存在");
            }
        }

        Menu menu = new Menu();
        BeanUtils.copyProperties(menuDTO, menu);
        menu.setCreatorId(StpUtil.getLoginIdAsLong());
        
        save(menu);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateMenu(Long id, MenuDTO menuDTO) {
        Menu menu = getById(id);
        if (menu == null) {
            throw new BusinessException("菜单不存在");
        }

        // 检查菜单编码是否重复
        if (!menu.getCode().equals(menuDTO.getCode())) {
            if (count(new LambdaQueryWrapper<Menu>()
                    .eq(Menu::getCode, menuDTO.getCode())) > 0) {
                throw new BusinessException("菜单编码已存在");
            }
        }

        // 检查父级菜单是否存在且不能设置自己为父级菜单
        if (menuDTO.getParentId() != 0) {
            if (menuDTO.getParentId().equals(id)) {
                throw new BusinessException("不能设置自己为父级菜单");
            }
            Menu parentMenu = getById(menuDTO.getParentId());
            if (parentMenu == null) {
                throw new BusinessException("父级菜单不存在");
            }
        }

        BeanUtils.copyProperties(menuDTO, menu);
        menu.setModifierId(StpUtil.getLoginIdAsLong());
        
        updateById(menu);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteMenu(Long id) {
        // 检查是否存在子菜单
        if (count(new LambdaQueryWrapper<Menu>()
                .eq(Menu::getParentId, id)) > 0) {
            throw new BusinessException("请先删除子菜单");
        }

        removeById(id);
    }

    @Override
    public List<MenuVO> getMenuTree() {
        // 获取所有菜单
        List<Menu> menus = list(new LambdaQueryWrapper<Menu>()
                .orderByAsc(Menu::getSort));
        
        return buildMenuTree(menus);
    }

    @Override
    public List<MenuVO> getUserMenus() {
        // 获取用户可见的菜单
        List<Menu> menus = list(new LambdaQueryWrapper<Menu>()
                .eq(Menu::getStatus, true)
                .eq(Menu::getIsVisible, true)
                .orderByAsc(Menu::getSort));
        
        return buildMenuTree(menus);
    }

    /**
     * 构建菜单树
     */
    private List<MenuVO> buildMenuTree(List<Menu> menus) {
        List<MenuVO> menuVOList = menus.stream().map(menu -> {
            MenuVO menuVO = new MenuVO();
            BeanUtils.copyProperties(menu, menuVO);
            return menuVO;
        }).collect(Collectors.toList());

        // 构建父子关系
        Map<Long, List<MenuVO>> parentMap = menuVOList.stream()
                .collect(Collectors.groupingBy(MenuVO::getParentId));

        // 设置子菜单
        menuVOList.forEach(menuVO -> 
            menuVO.setChildren(parentMap.getOrDefault(menuVO.getId(), new ArrayList<>())));

        // 返回顶级菜单
        return parentMap.getOrDefault(0L, new ArrayList<>());
    }
} 